#ifndef PLUGINS_H
#define PLUGINS_H
#include <QDir>
#include <QDebug>
#include <QPluginLoader>
#include <QApplication>
#include "Include/IPluginBase.h"

template<class T = IPluginBase>
class PluginWrapper
{
public:
    PluginWrapper(T *plugin = NULL):cls(plugin){}
    PluginWrapper(const PluginWrapper<T> & wrapper):cls(wrapper.cls){}
    PluginWrapper& operator=(PluginWrapper<T> const &rhs) {
        cls = rhs.cls;
        return *this;
    }

    operator T() { return *cls; }
    operator QWidget*(){ return cls->widget(); }
    T* operator->() const { return cls; }
    void slot(const QString& name, QGenericArgument a, QGenericArgument a2 = QGenericArgument(), QGenericArgument a3 = QGenericArgument())
    {
        QMetaObject::invokeMethod(cls->widget(), name.toLatin1(), Qt::QueuedConnection, a, a2, a3);
    }
    bool isNull(){ return cls == NULL;}
private:
    T * cls;
};

static QMap<QString, QObject*>_loadedPlugins = QMap<QString, QObject*>();

template<class T>
static PluginWrapper<T> loadPlugin(const QString & name)
{
    if (_loadedPlugins.contains(name)){
        PluginWrapper<T> w(qobject_cast<T*>(_loadedPlugins[name]));
        return w;
    }
    QString path = name;
    foreach(QString p, QApplication::libraryPaths()){
        if (QFile::exists(p+"/"+name)){
            path = p+"/"+name;
            break;
        }
    }

    qDebug() << path;
    QPluginLoader pluginLoader(path);
    QObject *plugin = pluginLoader.instance();
    _loadedPlugins[name] = plugin;
    qDebug() << "Loading" << name << (plugin ? "Ok" : "Fail: "+pluginLoader.errorString());
    PluginWrapper<T> w(qobject_cast<T*>(plugin));
    return w;
}

#endif
